/* Copyright (c) 2006, 2009, Carl Burch. License information is located in the
 * com.cburch.logisim.Main source code and at www.cburch.com/logisim/. */
 
package com.cburch.logisim.std.gates;

import java.util.Arrays;
import java.util.List;

import com.cburch.logisim.data.AbstractAttributeSet;
import com.cburch.logisim.data.Attribute;
import com.cburch.logisim.data.AttributeOption;
import com.cburch.logisim.data.Attributes;
import com.cburch.logisim.data.BitWidth;
import com.cburch.logisim.data.Direction;
import com.cburch.logisim.instance.StdAttr;
import com.cburch.logisim.util.IntegerFactory;
import com.cburch.logisim.util.Strings;

class GateAttributes extends AbstractAttributeSet {
    static final int MAX_INPUTS = 9;
    static final int DELAY = 1;

    static final AttributeOption SIZE_NARROW
        = new AttributeOption(IntegerFactory.create(30),
            Strings.getter("gateSizeNarrowOpt", Strings.stdSource));
    static final AttributeOption SIZE_WIDE
        = new AttributeOption(IntegerFactory.create(50),
            Strings.getter("gateSizeWideOpt", Strings.stdSource));
    public static final Attribute ATTR_SIZE
        = Attributes.forOption("size", Strings.getter("gateSizeAttr", Strings.stdSource),
            new AttributeOption[] { SIZE_NARROW, SIZE_WIDE });

    private static final Integer INPUTS_2 = IntegerFactory.create(2);
    private static final Integer INPUTS_3 = IntegerFactory.create(3);
    private static final Integer INPUTS_5 = IntegerFactory.create(5);
    private static final Integer INPUTS_7 = IntegerFactory.create(7);
    private static final Integer INPUTS_9 = IntegerFactory.create(9);
    public static final Attribute ATTR_INPUTS
        = Attributes.forOption("inputs", Strings.getter("gateInputsAttr", Strings.stdSource),
            new Object[] { INPUTS_2, INPUTS_3, INPUTS_5, INPUTS_7, INPUTS_9 });

    static final AttributeOption XOR_ONE
        = new AttributeOption("1", Strings.getter("xorBehaviorOne", Strings.stdSource));
    static final AttributeOption XOR_ODD
        = new AttributeOption("odd", Strings.getter("xorBehaviorOdd", Strings.stdSource));
    public static final Attribute ATTR_XOR
        = Attributes.forOption("xor", Strings.getter("xorBehaviorAttr", Strings.stdSource),
                new Object[] { XOR_ONE, XOR_ODD });
    
    private static final List ATTRIBUTES = Arrays.asList(new Attribute[] {
            StdAttr.FACING, StdAttr.WIDTH, ATTR_SIZE, ATTR_INPUTS
    });
    
    private static final List XOR_ATTRIBUTES = Arrays.asList(new Attribute[] {
            StdAttr.FACING, StdAttr.WIDTH, ATTR_SIZE, ATTR_INPUTS, ATTR_XOR
    });

    AbstractGate gate = null;
    Direction facing = Direction.EAST;
    BitWidth width = BitWidth.ONE;
    AttributeOption size = SIZE_WIDE;
    int inputs = 5;
    AttributeOption xorBehave;
    
    GateAttributes(boolean isXor) {
        xorBehave = isXor ? XOR_ONE : null;
    }

    protected void copyInto(AbstractAttributeSet destObj) {
        GateAttributes dest = (GateAttributes) destObj;
        dest.gate = null;
    }

    public List getAttributes() {
        return xorBehave == null ? ATTRIBUTES : XOR_ATTRIBUTES;
    }

    public Object getValue(Attribute attr) {
        if(attr == StdAttr.FACING) return facing;
        if(attr == StdAttr.WIDTH) return width;
        if(attr == ATTR_SIZE) return size;
        if(attr == ATTR_INPUTS) return IntegerFactory.create(inputs);
        if(attr == ATTR_XOR) return xorBehave;
        return null;
    }

    public void setValue(Attribute attr, Object value) {
        if(attr == StdAttr.WIDTH) {
            width = (BitWidth) value;
        } else if(attr == StdAttr.FACING) {
            facing = (Direction) value;
        } else if(attr == ATTR_SIZE) {
            size = (AttributeOption) value;
        } else if(attr == ATTR_INPUTS) {
            inputs = ((Integer) value).intValue();
        } else if(attr == ATTR_XOR) {
            xorBehave = (AttributeOption) value;
        } else {
            throw new IllegalArgumentException("unrecognized argument");
        }
        if(gate != null) gate.attributeValueChanged(attr, value);
        fireAttributeValueChanged(attr, value);
    }
}
